package com.gzu.shop.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gzu.shop.constant.JwtClaimsConstant;
import com.gzu.shop.context.BaseContext;
import com.gzu.shop.entity.*;
import com.gzu.shop.mapper.*;
import com.gzu.shop.recommend.OfflineRecommend;
import com.gzu.shop.service.ThingService;
import com.gzu.shop.service.UserBehaviorService;
import com.gzu.shop.util.JwtUtil;
import com.gzu.shop.util.UserCF;
import jakarta.annotation.Resource;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
* @author pcg
* @description 针对表【t_thing(商品表)】的推荐算法
* @createDate 2024-06-25 00:23:13
*/
@Service
public class ThingServiceImpl extends ServiceImpl<ThingMapper, Thing>
    implements ThingService{
    @Resource
    private ThingMapper thingMapper;
    @Resource
    private ThingCollectMapper thingCollectMapper;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private UserMapper userMapper;
    @Resource
    private ThingWishMapper thingWishMapper;

    @Resource
    private UserBehaviorService userBehaviorService;
    @Resource
    private ThingSimilarityMapper thingSimilarityMapper;

    @Override
    public List<Thing> recommend() {
        Map<String, Object> threadLocal = BaseContext.getThreadLocal();
        if (ObjectUtil.isEmpty(threadLocal)) {
            // 没有用户登录
            return new ArrayList<>();
        }
        Integer use1Id = (Integer) threadLocal.get(JwtClaimsConstant.USER_ID);
        Long useId = Long.valueOf(use1Id);
        System.out.println("userid + " + useId);
        // 用户的哪些行为可以认为他跟商品产生了关系？收藏、加入购物车、下单
        // 1. 获取所有的收藏信息,没有被取消
        List<ThingCollect> allCollects = thingCollectMapper.selectAll();
        // 2. 获取所有的订单信息，且订单信息不是取消和已退款
        List<Order> allCarts = orderMapper.selectAll();
        // 3. 获取所有的心愿信息
        List<ThingWish> allWishes = thingWishMapper.selectAll();
        // 4. 获取所有的评论信息
//        List<Comment> allComments = commentMapper.selectAll(null);
//         5. 获取所有的用户信息
        List<User> allUsers = userMapper.selectAll();
        // 6. 获取所有的商品信息
        List<Thing> allGoods = thingMapper.selectAll();

        // 定义一个存储每个商品和每个用户关系的List
        List<RelateDTO> data = new ArrayList<>();
        // 定义一个存储最后返回给前端的商品List
//        List<Thing> result = new ArrayList<>();

        // 开始计算每个商品和每个用户之间的关系数据
        for (Thing goods : allGoods) {
            Long goodsId = goods.getId();
            for (User user : allUsers) {
                Long userId = user.getId();
                int index = 1;
                // 1. 判断该用户有没有收藏该商品，收藏的权重我们给 1
                Optional<ThingCollect> collectOptional = allCollects.stream().filter(x -> x.getThingId().equals(goodsId) && x.getUserId().equals(userId)).findFirst();
                if (collectOptional.isPresent()) {
                    index += 1;
                }
                // 2. 判断该用户有没有给该商品加入订单，加入购物车的权重我们给 2
                Optional<Order> cartOptional = allCarts.stream().filter(x -> x.getThingId().equals(goodsId) && x.getUserId().equals(userId)).findFirst();
                if (cartOptional.isPresent()) {
                    index += 2;
                }
                // 3. 判断该用户有没有对商品有心愿，订单的权重我们给 3
                Optional<ThingWish> ordersOptional = allWishes.stream().filter(x -> x.getThingId().equals(goodsId) && x.getUserId().equals(userId)).findFirst();
                if (ordersOptional.isPresent()) {
                    index += 3;
                }
//                // 4. 判断该用户有没有对该商品评论过，评论的权重我们给 2
//                Optional<Comment> commentOptional = allComments.stream().filter(x -> x.getGoodsId().equals(goodsId) && x.getUserId().equals(userId)).findFirst();
//                if (commentOptional.isPresent()) {
//                    index += 2;
//                }
                if (index > 1) {
                    RelateDTO relateDTO = new RelateDTO(userId, goodsId, index);
                    data.add(relateDTO);
                }
            }
        }

        // 数据准备结束后，就把这些数据一起喂给这个推荐算法
        List<Long> goodsIds = UserCF.recommend(useId, data);
        // 把商品id转换成商品
        List<Thing> recommendResult = goodsIds.stream().map(goodsId -> allGoods.stream()
                        .filter(x -> x.getId().equals(goodsId)).findFirst().orElse(null))
                .limit(10).collect(Collectors.toList());

        if (CollectionUtil.isEmpty(recommendResult)) {
            // 随机给它推荐10个
            return getRandomGoods(10);
        }
        if (recommendResult.size() < 10) {
            int num = 10 - recommendResult.size();
            List<Thing> list = getRandomGoods(num);
            recommendResult.addAll(list);
        }
        return recommendResult;
    }

    private List<Thing> getRandomGoods(int num) {
        List<Thing> list = new ArrayList<>(num);
        List<Thing> goods = thingMapper.selectAll();
        for (int i = 0; i < num; i++) {
            int index = new Random().nextInt(goods.size());
            list.add(goods.get(index));
        }
        return list;
    }

    public List<Thing> offlineRecommend() {
       // 获取当前用户id
        Map<String, Object> threadLocal = BaseContext.getThreadLocal();
        if (ObjectUtil.isEmpty(threadLocal)) {
            // 没有用户登录
            return new ArrayList<>();
        }
        Integer use1Id = (Integer) threadLocal.get(JwtClaimsConstant.USER_ID);
        Long useId = Long.valueOf(use1Id);
        List<UserBehavior> goods = userBehaviorService.getGoods(useId);
        // 用户行为看过的商品id
        List<Long> goodsIds = goods.stream().map(x -> Long.valueOf(x.getThingId())).collect(Collectors.toList());
        // 查询相似度
        List<ThingSimilarity> thingSimilarities = thingSimilarityMapper.selectSimilarity();
        // 获取所有商品
        List<Thing> allThingList = thingMapper.selectAll();
//        List<Long> allThingsId = allThingList.stream().map(x -> x.getId()).collect(Collectors.toList());

        List<Long> offlineRecommendId = OfflineRecommend.updateRecommend(goodsIds, thingSimilarities);
        List<Thing> offlineRecommend = offlineRecommendId.stream().map(x -> allThingList.stream().filter(y -> y.getId().equals(x)).findFirst().orElse(null)).collect(Collectors.toList());

        if (CollectionUtil.isEmpty(offlineRecommend)) {
            // 随机推荐
            return getRandomGoods(10);
        }
        if (offlineRecommend.size() < 10) {
            int num = 10 - offlineRecommend.size();
            List<Thing> list = getRandomGoods(num);
            offlineRecommend.addAll(list);
        }

       return offlineRecommend;
    }
}




